// 矩形光
// 注意：1、RectAreaLight 只能影响 MeshStandardMaterial 和 MeshPhysicalMaterial 2、矩形光的辅助对象应该添加为光的子节点而不是场景

// GUI  调试面板库
// 辅助类：THREE.Color 不能直接被 dat.GUI 修改，所以需要转换成 HEX 字符串（#ffffff 格式）

import { useEffect } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import * as dat from 'dat.gui'; // 导入 dat.GUI
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';

function SimpleCubeWithLight() {
  useEffect(() => {
    // ---------------初始化场景、相机、渲染器
    const scene = new THREE.Scene();

    const fov = 45;
    const aspect = 2; // canvas 的默认宽高 300:150
    const near = 0.1;
    const far = 100;
    const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    camera.position.set(0, 10, 10);

    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // 轨道控制器，实现围绕观察点旋转相机
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.target.set(0, 5, 5); // 观察点
    controls.update();

    // -----------------------物体
    // 二维平面底座
    // 1、设置纹理
    const planeSize = 40;
    const loader = new THREE.TextureLoader();
    const texture = loader.load('/masaike.png');
    texture.wrapS = THREE.RepeatWrapping; // 纹理重复-水平包裹
    texture.wrapT = THREE.RepeatWrapping;
    texture.magFilter = THREE.NearestFilter;
    const repeats = planeSize / 2;
    texture.repeat.set(repeats, repeats);
    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
    const planeMat = new THREE.MeshStandardMaterial({
      map: texture,
      side: THREE.DoubleSide,
    });
    const mesh = new THREE.Mesh(planeGeo, planeMat);
    mesh.rotation.x = Math.PI * -0.5;
    scene.add(mesh);
    // 几何体
    {
      const cubeSize = 4;
      const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
      const cubeMat = new THREE.MeshStandardMaterial({ color: '#8AC' });
      const mesh = new THREE.Mesh(cubeGeo, cubeMat);
      mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
      scene.add(mesh);
    }
    {
      const sphereRadius = 3;
      const sphereWidthDivisions = 32;
      const sphereHeightDivisions = 16;
      const sphereGeo = new THREE.SphereGeometry(
        sphereRadius,
        sphereWidthDivisions,
        sphereHeightDivisions
      );
      const sphereMat = new THREE.MeshStandardMaterial({ color: '#CA8' });
      const mesh = new THREE.Mesh(sphereGeo, sphereMat);
      mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
      scene.add(mesh);
    }

    // ----------------------------光源
    RectAreaLightUniformsLib.init(); // 矩形光所需的额外的着色库
    // 1创建矩形光
    const color = 0xffffff;
    const intensity = 5;
    const width = 12;
    const height = 4;
    const light = new THREE.RectAreaLight(color, intensity, width, height);
    light.position.set(0, 10, 0);
    light.rotation.x = THREE.MathUtils.degToRad(-90);
    scene.add(light);

    const helper = new RectAreaLightHelper(light);
    light.add(helper);

    // ------------------------------gui
    // 2创建辅助类帮助gui修改属性
    // 修改颜色
    class ColorGUIHelper {
      constructor(object, prop) {
        this.object = object;
        this.prop = prop;
      }
      // 当读取value时，返回this.prop (light.color) 的 HEX 字符串格式（如 "#ffffff")
      get value() {
        return `#${this.object[this.prop].getHexString()}`;
      }
      // 当修改value时，将 HEX 字符串（如 "#ff0000"）设置给 this.prop (light.color)
      set value(hexString) {
        this.object[this.prop].set(hexString);
      }
    }
    // 弧度、角度转换
    class DegRadHelper {
      constructor(obj, prop) {
        this.obj = obj;
        this.prop = prop;
      }
      get value() {
        return THREE.MathUtils.radToDeg(this.obj[this.prop]); //radToDeg弧度转角度
      }
      set value(v) {
        this.obj[this.prop] = THREE.MathUtils.degToRad(v); // degToRad角度转弧度
      }
    }
    // 添加折叠文件，修改位置
    function makeXYZGUI(gui, vector3, name, onChangeFn) {
      const folder = gui.addFolder(name); // 在控件内创建一个折叠文件夹
      folder.add(vector3, 'x', -10, 10).onChange(onChangeFn); // 为 vector3.x 添加一个滑块控件，范围从 -10 到 10
      folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
      folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
      folder.open();
    }

    // 3添加控件gui
    const gui = new dat.GUI(); // 创建控件对象gui
    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
    gui.add(light, 'intensity', 0, 10, 0.01);
    gui.add(light, 'width', 0, 20); // 矩形宽度
    gui.add(light, 'height', 0, 20); // 矩形高度
    gui
      .add(new DegRadHelper(light.rotation, 'x'), 'value', -180, 180)
      .name('x rotation'); // 矩形x方向旋转
    gui
      .add(new DegRadHelper(light.rotation, 'y'), 'value', -180, 180)
      .name('y rotation');
    gui
      .add(new DegRadHelper(light.rotation, 'z'), 'value', -180, 180)
      .name('z rotation');

    // 矩形位置
    makeXYZGUI(gui, light.position, 'position');
    // --------------------------------渲染
    function animate() {
      requestAnimationFrame(animate);
      renderer.render(scene, camera);
    }
    animate();

    // 清理函数
    return () => {
      document.body.removeChild(renderer.domElement);
      gui.destroy(); // 由于useEffect 执行两次，所以在组件卸载时销毁 GUI
    };
  }, []);

  return <div />;
}

export default SimpleCubeWithLight;
